2023/05/23 更新: 為了避免本文章散落在不同網站,之後統一由部落格更新,再麻煩從部落格查看~
本文章同時發佈於:
文章為自己的經驗與夥伴整理的內容,設計沒有標準答案,如有可以改進的地方,請告訴我,我會盡我所能的修改,謝謝大家~
大家好,繼昨天DAY04 Docker-Compose 的介紹後,我們終於有了一個開發環境,接下來要實作夠過各種 Docs tool 來建構各種文件與程式介面。
文件與實作同步,為不同團隊提供一個簡潔的系統介紹,而不是遇到任何問題就
看code
以前接受了許多專案,文檔提供不完全,導致許多 API 根本不清楚作用,而是要透過看code
來了解整體情境,這花費了巨量的時間。
也不是說看 code 不好,在Clean Code書中也有提到 :
code 必須要清楚表達意圖,而不是靠各種註解解決
而文件跟註解有幾分相似,是否如果 code 寫得好就不需要文件了呢?
我認為還是要的,以下是我覺得需要寫成文件的部分:
因為寫文件的成本往往高於寫 code
我認為有以下關係:
所以我已以下原則來寫文件,我認為可以減低以上問題的成本 XD:
為了邏輯而畫圖
,而是寫好邏輯就自動產生圖用文件產生程式介面
。沒錯!你可以這樣做,在 GraphQL 問世後,大家慢慢發現可以這樣做,要更改程式嗎?那請先更新 GraphQL schema,如此一來文件永遠不會落後,前後端的 code 也可以透過這個文件產生。
而 gRPC 也是有同樣的概念在裡頭,gRPC 是透過定義好 Protobuf 文件來產生程式碼。
但較少人知道,Restful API 其實也是可以這樣做的,即是定義好 Open API,並透過上述swagger-generator來產生程式碼。
.jpg/.png
中編輯圖片並同步更新在 Markdown 中不同語言的Server端與Client端
,對於規範好不同團隊語言的接口很方便。還記得小時候玩的數碼育成機嗎?一開始會有一顆數碼蛋,我們要慢慢培育他,隨著時間這顆數碼蛋就會孵化出數碼獸,並與我們一起成長。Digimon-Service 希望可以提供這些功能。
所以基於這些需求,我們開始把文件撰寫出來~
Digimon-Service 結構圖 - 使用vscode-drawio完成:
提供的功能:
實作我們採用 Restful API,以下是 API - 使用Insomnia Designer完成:
# swagger.yaml
openapi: 3.0.1
info:
title: Digimon Service API
description: 提供孵化數碼蛋與培育等數碼寶貝養成服務
version: 1.0.0
servers:
- url: http://localhost:5000/api/v1
paths:
/digimons:
post:
summary: 產生數碼蛋
description: 產生一顆數碼蛋,供request端養成
requestBody:
description: 客製數碼蛋的請求
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DigimonInfoRequest"
responses:
"200":
description: 數碼蛋的資訊
content:
application/json:
schema:
$ref: "#/components/schemas/DigimonInfo"
"500":
$ref: "#/components/responses/500InternalError"
/digimons/{digimonID}:
get:
summary: 查看數碼獸狀態
parameters:
- in: path
name: digimonID
schema:
type: string
required: true
description: 數碼蛋的唯一識別碼,格式為uuid v4
responses:
"200":
description: 數碼蛋的資訊
content:
application/json:
schema:
$ref: "#/components/schemas/DigimonInfo"
"500":
$ref: "#/components/responses/500InternalError"
/digimons/{digimonID}:foster:
post:
summary: 培育數碼獸
description: 對數碼獸進行培育,以改善數碼獸的狀態
parameters:
- in: path
name: digimonID
schema:
type: string
required: true
description: 數碼蛋的唯一識別碼,格式為uuid v4
requestBody:
description: 培育的食物
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/FosterRequest"
responses:
"200":
description: 培育完畢後的數碼獸的資訊
content:
application/json:
schema:
$ref: "#/components/schemas/DigimonInfo"
"500":
$ref: "#/components/responses/500InternalError"
components:
schemas:
DigimonInfo:
type: object
properties:
id:
type: string
description: 數碼蛋的唯一識別碼,格式為uuid v4
example: 56e400bd-c98b-49b9-ad8c-0607800e026f
name:
type: string
description: 數碼蛋的名稱
example: Agumon
status:
type: string
description: 數碼蛋此時的狀態
example: healthy
FosterRequest:
type: object
properties:
food:
type: object
description: 培育所使用的食物
properties:
name:
type: string
description: 食物名稱
example: apple
DigimonInfoRequest:
type: object
properties:
name:
type: string
description: 數碼蛋的名字
required:
- name
example:
name: Agumon
Error:
type: object
properties:
message:
type: string
description: 錯誤訊息
code:
type: number
description: >
錯誤代碼:
* `3000` - Internal error
required:
- message
- code
example:
message: "Internal error. Parsing failed"
code: 3000
responses:
500InternalError:
description: 伺服器錯誤
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
Insomnia Designer的設計介面非常友好,並且!當你點了上方的DEBUG
他竟人產生了測試端點!連端點都不用慢慢加了,太神啦~!
資料庫如下 - 使用vscode-drawio完成:
流程上如下 - 使用mermaid-js完成:
產生數碼蛋
培育數碼獸
查看數碼獸
有了這些便捷的工具後,
文件就不是個很
花費時間又重工
的事情了,而是可以直接使用在開發上
的好幫手!
接下來要介紹如何透過swagger-generator生產出 Golang Server 的介面並且透過 Clean Architecture 來實作,並透過Insomnia Designer測試
謝謝你的閱讀,也歡迎分享討論指正~
swagger.yaml有些錯誤訊息,以下是修改過後正常的版本,供參考。
openapi: 3.0.1
info:
title: Digimon Service API
description: 提供孵化數碼蛋與培育等數碼寶貝養成服務
version: 1.0.0
contact: {
email: "123@gmail.com"
}
tags:
- name: digimon
description: Everything about your digimons
servers:
- url: http://localhost:5000/api/v1
paths:
/digimons:
post:
operationId: "1"
tags: [
"digimon"
]
summary: 產生數碼蛋
description: 產生一顆數碼蛋,供request端養成
requestBody:
description: 客製數碼蛋的請求
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DigimonInfoRequest"
responses:
"200":
description: 數碼蛋的資訊
content:
application/json:
schema:
$ref: "#/components/schemas/DigimonInfo"
"500":
$ref: "#/components/responses/500InternalError"
/digimons/{digimonID}:
get:
operationId: "2"
tags: [
"digimon"
]
summary: 查看數碼獸狀態
description: 供request端查看
parameters:
- in: path
name: digimonID
schema:
type: string
required: true
description: 數碼蛋的唯一識別碼,格式為uuid v4
responses:
"200":
description: 數碼蛋的資訊
content:
application/json:
schema:
$ref: "#/components/schemas/DigimonInfo"
"500":
$ref: "#/components/responses/500InternalError"
/digimons/{digimonID}/foster:
post:
operationId: "3"
tags: [
"digimon"
]
summary: 培育數碼獸
description: 對數碼獸進行培育,以改善數碼獸的狀態
parameters:
- in: path
name: digimonID
schema:
type: string
required: true
description: 數碼蛋的唯一識別碼,格式為uuid v4
requestBody:
description: 培育的食物
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/FosterRequest"
responses:
"200":
description: 培育完畢後的數碼獸的資訊
content:
application/json:
schema:
$ref: "#/components/schemas/DigimonInfo"
"500":
$ref: "#/components/responses/500InternalError"
components:
schemas:
DigimonInfo:
type: object
properties:
id:
type: string
description: 數碼蛋的唯一識別碼,格式為uuid v4
example: 56e400bd-c98b-49b9-ad8c-0607800e026f
name:
type: string
description: 數碼蛋的名稱
example: Agumon
status:
type: string
description: 數碼蛋此時的狀態
example: healthy
FosterRequest:
type: object
properties:
food:
type: object
description: 培育所使用的食物
properties:
name:
type: string
description: 食物名稱
example: apple
DigimonInfoRequest:
type: object
properties:
name:
type: string
description: 數碼蛋的名字
required:
- name
example:
name: Agumon
Error:
type: object
properties:
message:
type: string
description: 錯誤訊息
code:
type: number
description: >
錯誤代碼:
* `3000` - Internal error
required:
- message
- code
example:
message: "Internal error. Parsing failed"
code: 3000
responses:
500InternalError:
description: 伺服器錯誤
content:
application/json:
schema:
$ref: "#/components/schemas/Error"